Skip to content

#2319: Initial podman setup, more iterations follow#2321

Draft
jh-RLI wants to merge 26 commits into
developfrom
feature-2319-add-podman-setup
Draft

#2319: Initial podman setup, more iterations follow#2321
jh-RLI wants to merge 26 commits into
developfrom
feature-2319-add-podman-setup

Conversation

@jh-RLI

@jh-RLI jh-RLI commented May 19, 2026

Copy link
Copy Markdown
Contributor

Summary of the discussion

Describe the findings of the discussion in the issue or meeting.

Type of change (CHANGELOG.md)

Features

  • Add a new functionality
    (#)

Changes

  • Update existing functionality
    (#)

Bugs

  • Fixed a problem with
    (#)

Removed

  • Remove a broken link
    (#)

Documentation updates

  • Updated documentation for
    (#)

Workflow checklist

Automation

Closes #2319

PR-Assignee

Reviewer

  • 🐙 Follow the
    Reviewer Guidelines
  • 🐙 Provided feedback and show sufficient appreciation for the work done

jh-RLI and others added 26 commits May 19, 2026 19:29
… README

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Provides an alternative to podman-compose for servers running a systemd
user session. Each service is a standalone Podman quadlet unit file that
systemd manages directly — no compose binary required at runtime.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…paths #2319

- Add podman/serviceConfigs/ontop/ with empty mapping.obda skeleton,
  ontop.properties.template, .gitignore (excludes ontology.owl,
  postgresql.jar, ontop.properties), and setup README
- Update podman-compose.yaml and oep-ontop.container to mount from
  podman/serviceConfigs/ontop/ instead of docker/serviceConfigs/ontop/

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ages #2319

- Add .github/workflows/build-production-image.yaml to build and push
  ghcr.io/openenergyplatform/oeplatform-production (app + Vite build) and
  ghcr.io/openenergyplatform/oeplatform-ontop (Ontop + JDBC driver) on v* tags
- Update podman-compose.yaml and quadlet container files to pull from
  registry instead of building locally on the server
- Update quadlets/install.sh to reflect pull-based deployment

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>


- Add explicit container_name to postgres service so dnsname CNI plugin
  registers it as "postgres" (matches OEP_DJANGO_HOST / LOCAL_DB_HOST)
- Declare external oep network; set default_network=oep in containers.conf
  to work around podman-compose 1.5.0 not passing --network to podman run
- Add networks section with oep to all services (explicit long-form)
- Add lookup_index named volume; move lookup config to podman/serviceConfigs/
  to keep podman and docker setups fully separate
- Prefix all short image names with docker.io/ (fixes short-name resolution)
- Fix docker/Dockerfile.ontop: qualify FROM ontop/ontop as docker.io/ontop/ontop

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…2319

- Correct Podman version requirement from 4.0 to 3.4+
- Document CNI plugin version mismatch fix (containernetworking-plugins
  0.9.1 vs cniVersion 1.0.0): download v1.9.1 binaries to ~/.config/cni/plugins
- Document podman-compose 1.5.0 network assignment bug and workaround:
  pre-create oep network + set default_network in containers.conf
- Update all commands to use --env-file podman/.env
- Add Quadlets section explaining why it avoids the network workaround
- Update Deploy section: pull pre-built images instead of building locally

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Use lookup-index named volume instead of docker/data/index bind mount
  (keeps podman and docker index data separate; fixes write.lock permission error)
- Point config volume to podman/serviceConfigs/lookup/ instead of docker/
- Add lookup-index.volume quadlet unit

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add gitignore negation rules so .env.example and oep.env.example are
  tracked while .env files remain ignored (.env* glob was too broad)
- Add podman/.env.example to version control
- Document all required environment variables in README with descriptions

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Serve the rootless quadlet deployment over HTTPS without exposing the
container directly:

- Add host nginx reverse proxy config (podman/nginx/oeplatform.conf) that
  terminates TLS on :443 and proxies to the container on 127.0.0.1:8080.
  No certbot — operator supplies their own certificate.
- Bind oep-oeplatform PublishPort to 127.0.0.1:8080 so the app is only
  reachable through nginx.
- Make Django HTTPS/host settings env-driven: OEP_DEBUG, OEP_URL,
  OEP_ALLOWED_HOSTS, OEP_BEHIND_TLS_PROXY (sets SECURE_PROXY_SSL_HEADER and
  secure cookies), OEP_CSRF_TRUSTED_ORIGINS. Defaults preserve dev behavior.
- Document the HTTPS setup and new env vars in the quadlets README and
  oep.env.example.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The production server sits behind an upstream reverse proxy / load balancer
that terminates HTTPS, so the host nginx no longer manages certificates:

- Drop the SSL server block and cert paths; nginx now listens on plain HTTP
  and proxies to the container on 127.0.0.1:8080.
- Preserve the upstream's X-Forwarded-Proto via a map so Django still sees
  the request as HTTPS, instead of clobbering it to $scheme (http).
- Update the quadlet comment and README HTTPS section accordingly (remove
  certbot/self-signed steps).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…age #2319

ontology/apps.py OntologyConfig.ready() aborts Django startup (raising
ImportError) when the OEO release folder or oeo_ext.owl are absent. Because
collectstatic/compress run django.setup() at build time, the image build
failed unless these artifacts existed beforehand.

Download build-files.zip (→ ontologies/oeo/<version>/…) and seed oeo_ext.owl
from the template *before* the collectstatic step. Use unzip -o / cp -f so a
stale copy pulled in by COPY . /app doesn't trigger an interactive overwrite
prompt that hangs the non-interactive build.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…2319

The postgresql.jar driver is baked into the ontop image from
docker/serviceConfigs/ontop/ (docker/Dockerfile.ontop copies it to
/opt/ontop/lib/); it is NOT read from podman/serviceConfigs/ontop/, which is
only the runtime config mount. Previous docs implied the jar belonged in the
podman config dir, causing confusion.

- Rewrite podman/serviceConfigs/ontop/README.md: split into runtime files
  (ontology.owl, ontop.properties) vs the build-time driver in docker/.
- Drop postgresql.jar from podman/serviceConfigs/ontop/.gitignore (not used
  there).
- Broaden the root .gitignore rule to **/serviceConfigs/ontop/postgresql.jar
  so the driver stays out of the repo in any location.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
#2319

COPY . /app was pulling local, untracked ontologies/ and media/ trees into the
image, which bloated the context and collided with the OEO release the
Dockerfile bakes (forcing the unzip -o workaround). Ignore them so the baked
artifacts are the single source of truth and the build context stays small.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The upstream LB terminates TLS and forwards cleartext HTTP to this host on
port 443 (the only port open to the LB), not 80. Switch the nginx listen
directive from 80 to 443 — still without ssl / no certificate, since TLS is
handled upstream. nginx runs as root so binding privileged :443 in front of
the rootless container (127.0.0.1:8080) is fine.

Update the quadlets README HTTPS section to match (listen 443, why the root
nginx shim is needed for a rootless container).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…2319

- Multi-stage Dockerfile.ontop fetches the PostgreSQL JDBC driver from Maven
  Central at build time (--build-arg JDBC_VERSION); no jar in the context.
- Bake the ontology and an empty default mapping so the endpoint starts with
  zero host files, regardless of database state.
- CI passes JDBC_VERSION as a build arg.
…ties #2319

- Supply the DB connection through ONTOP_DB_URL / ONTOP_DB_USER /
  ONTOP_DB_PASSWORD (read natively by ontop); remove ontop.properties.template.
- Fix the no-op ONTOP_OWL_FILE -> ONTOP_ONTOLOGY_FILE.
- Drop the ontop host bind mount and /opt/oeplatform path dependency; wait for
  postgres via ONTOP_WAIT_FOR.
- Mirror the same env-based config in podman-compose and docker-compose.dev.
- Add the ONTOP_DB_* block to the env examples.
Update the quadlets README, ontop service README and the ontop install guide
to reflect the baked artifacts, env-based DB connection and the empty default
mapping.
…2319

The lookup service bind-mounts its config from the repo. Instead of requiring a
manual /opt/oeplatform symlink, the unit ships an @@OEP_REPO@@ placeholder that
install.sh replaces with the checkout's absolute path at install time. Works
from any location with no manual steps — keeps the setup deterministic.
…oxy #2319

Script the nginx host setup so there are no manual steps: install-nginx.sh
installs nginx, writes the site config with server_name taken from OEP_URL in
oep.env (single source of truth), enables the site, drops the default one and
reloads. Idempotent and re-runnable; domain can also be passed as an argument.
Update the quadlets README HTTPS section to use it.
…2319

Support the two-account setup (rootless container user + separate sudo admin):
use sudo only when not already root, and look for oep.env under the invoking
user's home ($SUDO_USER) as well. Lets the admin run it as
`sudo bash install-nginx.sh <domain>` while the container user owns oep.env.
Django 4+ rejects CSRF_TRUSTED_ORIGINS entries without a scheme, which crashed
startup when OEP_CSRF_TRUSTED_ORIGINS held a bare host. Prepend https:// to any
entry lacking a scheme. Only affects deployments that set the var (podman);
docker setups don't set it, so the gated block is skipped unchanged.
…oxy #2319

The upstream Apache reverse proxy re-encrypts to the backend (opens an HTTPS
connection to this host on :443), so serving plain HTTP there fails with
"Error during SSL Handshake with remote server". Switch nginx back to
`listen 443 ssl` and have install-nginx.sh auto-generate a self-signed cert
(SANs for the public + internal FQDN) when none is provided; Apache's mod_proxy
does not verify the backend cert by default. Update the README HTTPS section.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Podman based deployment solution

1 participant